﻿using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web.Hosting;
using System.Xml;
using System.Xml.Serialization;

namespace NotifyPilot.WCF.Helpers
{
    public class Helpers
    {
        public const String NotifyLogSource = "TFS Notify Client";
        public static IEnumerable<Type> GetNotifyClientClasses(Type interfaceType)
        {
            //   var type = typeof (IClient);
            var types = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(s => s.GetTypes())
                .Where(p => interfaceType.IsAssignableFrom(p) && !p.IsAbstract &&
                            !p.IsInterface).ToArray();
            return types;
        }

        public static T DeserializeChangeObject<T>(String xmlObject)
        {
            var serializer = new XmlSerializer(typeof(T));
            using (var sr = new StringReader(xmlObject))
            {
                using (var reader = new XmlTextReader(sr))
                {
                    return (T)serializer.Deserialize(reader);
                }
            }
        }

        public static String SerializeObject<T>(T xmlObject)
        {
            var xmlSerializer = new XmlSerializer(xmlObject.GetType());
            var textWriter = new StringWriter();

            xmlSerializer.Serialize(textWriter, xmlObject);
            return textWriter.ToString();
        }

        public static Boolean SerializeObjectToFile<T>(T xmlObject, String filename)
        {
            var content = SerializeObject(xmlObject);
            var realFileName = HostingEnvironment.MapPath(filename);

            return WriteFile(realFileName, content);

        }

        public static T DeserialiseXmlFromFile<T>(String filename)
        {
            var realFileName = HostingEnvironment.MapPath(filename);
            var fileContent = ReadFile(realFileName);
            if (String.IsNullOrWhiteSpace(fileContent))
                return default(T);
            return DeserializeChangeObject<T>(fileContent);
        }

        public static String ReadFile(string fileName)
        {
            try
            {
                return File.Exists(fileName) ? File.ReadAllText(fileName) : null;
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static bool WriteFile(String fileName, String content)
        {
            try
            {
                File.WriteAllText(fileName, content);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
    /// <summary>
    /// Event raised when a change occurs to a Work Item
    /// </summary>
    [GeneratedCode("xsd", "2.0.50727.42")]
    [Serializable]
    [DebuggerStepThrough]
    [DesignerCategory("code")]
    [XmlType(AnonymousType = true)]
    [XmlRoot(Namespace = "", IsNullable = false)]
    // ReSharper disable PartialTypeWithSinglePart
    public class WorkItemChangedEvent
    // ReSharper restore PartialTypeWithSinglePart
    {
        public String GetPropertyStringValue(String refenceName)
        {
            var field = this.GetPropertyValue(refenceName);
            if (field != null)
            {
                return !String.IsNullOrWhiteSpace(field.NewValue) ?
                    field.NewValue : field.OldValue;
            }
            return null;
        }

        public Nullable<DateTime> GetPropertyDateTimeValue(String refenceName, bool utc = true)
        {
            var field = this.GetPropertyValue(refenceName);
            if (field != null)
            {
                var value = !String.IsNullOrWhiteSpace(field.NewValue) ?
                    field.NewValue : field.OldValue;

                var retValue = DateTime.Parse(value);

                if (!utc)
                {
                    var timeOffset = TimeSpan.Parse(this.TimeZoneOffset);
                    return retValue.Add(timeOffset);
                }

                return retValue;
            }
            return null;
        }

        public int GetPropertyIntValue(String refenceName)
        {
            var field = this.CoreFields.IntegerFields.FirstOrDefault(p => p.ReferenceName.Equals(refenceName));
            if (field != null)
            {
                return field.NewValue != 0 ?
                    field.NewValue : field.OldValue;
            }
            return -1;
        }

        public StringField GetPropertyValue(String refenceName)
        {
            var field = this.CoreFields.StringFields.FirstOrDefault(p => p.ReferenceName.Equals(refenceName));
            return field;
        }
        #region Public Properties

        /// <remarks/>
        public string PortfolioProject { get; set; }

        /// <remarks/>
        public string ProjectNodeId { get; set; }

        /// <remarks/>
        public string AreaPath { get; set; }

        /// <remarks/>
        public string Title { get; set; }

        /// <remarks/>
        public string WorkItemTitle { get; set; }

        /// <remarks/>
        public string Subscriber { get; set; }

        /// <remarks/>
        public string ChangerSid { get; set; }

        /// <remarks/>
        public string DisplayUrl { get; set; }

        /// <remarks/>
        public string TimeZone { get; set; }

        /// <remarks/>
        public string TimeZoneOffset { get; set; }

        /// <remarks/>
        public ChangeTypes ChangeType { get; set; }

        /// <remarks/>
        public CoreFieldsType CoreFields { get; set; }

        /// <remarks/>
        [XmlArrayItem("Field", IsNullable = false)]
        public TextField[] TextFields { get; set; }

        /// <remarks/>
        public ChangedFieldsType ChangedFields { get; set; }

        /// <remarks/>
        [XmlArrayItem("Name", IsNullable = false)]
        public string[] AddedFiles { get; set; }

        /// <remarks/>
        [XmlArrayItem("FileId", IsNullable = false)]
        public string[] DeletedFiles { get; set; }

        /// <remarks/>
        [XmlArrayItem("Resource", IsNullable = false)]
        public string[] AddedResourceLinks { get; set; }

        /// <remarks/>
        [XmlArrayItem("LinkId", IsNullable = false)]
        public string[] DeletedResourceLinks { get; set; }

        /// <remarks/>
        [XmlArrayItem("LinkId", IsNullable = false)]
        public string[] ChangedResourceLinks { get; set; }

        /// <remarks/>
        [XmlArrayItem("WorkItemId", IsNullable = false)]
        public string[] AddedRelations { get; set; }

        /// <remarks/>
        [XmlArrayItem("WorkItemId", IsNullable = false)]
        public string[] DeletedRelations { get; set; }

        /// <remarks/>
        [XmlArrayItem("WorkItemId", IsNullable = false)]
        public string[] ChangedRelations { get; set; }

        #endregion
    }

    /// <summary>
    /// Enumeration which lists the type of change that has occured
    /// </summary>
    [GeneratedCode("xsd", "2.0.50727.42")]
    [Serializable]
    [XmlType(Namespace = "")]
    public enum ChangeTypes
    {
        /// <summary>
        /// The Work Item has been created
        /// </summary>
        New,

        /// <summary>
        /// The Work Item has been changed
        /// </summary>
        Change
    }

    /// <summary>
    /// Type which contains the CoreFields of the Work Item
    /// </summary>
    [GeneratedCode("xsd", "2.0.50727.42")]
    [Serializable]
    [DebuggerStepThrough]
    [DesignerCategory("code")]
    [XmlType(Namespace = "")]
    // ReSharper disable PartialTypeWithSinglePart
    public partial class CoreFieldsType
    // ReSharper restore PartialTypeWithSinglePart
    {
        #region Public Properties

        /// <remarks/>
        [XmlArrayItem("Field", IsNullable = false)]
        public List<IntegerField> IntegerFields { get; set; }

        /// <remarks/>
        [XmlArrayItem("Field", IsNullable = false)]
        public List<StringField> StringFields { get; set; }

        #endregion
    }

    /// <summary>
    /// Type which contains the old and new values of the interger field that has changed
    /// </summary>
    [GeneratedCode("xsd", "2.0.50727.42")]
    [Serializable]
    [DebuggerStepThrough]
    [DesignerCategory("code")]
    [XmlType(Namespace = "")]
    // ReSharper disable PartialTypeWithSinglePart
    public partial class IntegerField
    // ReSharper restore PartialTypeWithSinglePart
    {
        #region Public Properties

        /// <remarks/>
        public string Name { get; set; }

        /// <remarks/>
        public string ReferenceName { get; set; }

        /// <remarks/>
        public int OldValue { get; set; }

        /// <remarks/>
        public int NewValue { get; set; }

        #endregion
    }

    /// <summary>
    /// Type which contains a list of the fields that have changed
    /// </summary>
    [GeneratedCode("xsd", "2.0.50727.42")]
    [Serializable]
    [DebuggerStepThrough]
    [DesignerCategory("code")]
    [XmlType(Namespace = "")]
    // ReSharper disable PartialTypeWithSinglePart
    public partial class ChangedFieldsType
    // ReSharper restore PartialTypeWithSinglePart
    {
        #region Public Properties

        /// <remarks/>
        [XmlArrayItem("Field", IsNullable = false)]
        public List<IntegerField> IntegerFields { get; set; }

        /// <remarks/>
        [XmlArrayItem("Field", IsNullable = false)]
        public List<StringField> StringFields { get; set; }

        #endregion
    }

    /// <summary>
    /// Type which contains the old and new values of the string field that has changed
    /// </summary>
    [GeneratedCode("xsd", "2.0.50727.42")]
    [Serializable]
    [DebuggerStepThrough]
    [DesignerCategory("code")]
    [XmlType(Namespace = "")]
    // ReSharper disable PartialTypeWithSinglePart
    public partial class StringField
    // ReSharper restore PartialTypeWithSinglePart
    {
        #region Public Properties

        /// <remarks/>
        public string Name { get; set; }

        /// <remarks/>
        public string ReferenceName { get; set; }

        /// <remarks/>
        public string OldValue { get; set; }

        /// <remarks/>
        public string NewValue { get; set; }

        #endregion
    }

    /// <summary>
    /// Type which contains information about the Work Item's text field
    /// </summary>
    [GeneratedCode("xsd", "2.0.50727.42")]
    [Serializable]
    [DebuggerStepThrough]
    [DesignerCategory("code")]
    [XmlType(Namespace = "")]
    // ReSharper disable PartialTypeWithSinglePart
    public partial class TextField
    // ReSharper restore PartialTypeWithSinglePart
    {
        #region Public Properties

        /// <remarks/>
        public string Name { get; set; }

        /// <remarks/>
        public string ReferenceName { get; set; }

        /// <remarks/>
        public string Value { get; set; }

        #endregion
    }



    public static class ConfigurationHelpers
    {
        public static String GetValue(String key)
        {
            return ConfigurationManager.AppSettings[key];
        }

        public static Double? GetFloat(String key)
        {
            double number;
            const NumberStyles numberStyle = NumberStyles.AllowDecimalPoint;
            var sValue = GetValue(key);
            if (String.IsNullOrWhiteSpace(sValue))
                return null;
            if (!Double.TryParse(sValue, numberStyle, CultureInfo.InvariantCulture, out number))
                return null;
            return number;
        }

        public static bool? GetBooleanValue(String key)
        {
            var sValue = GetValue(key);
            if (String.IsNullOrWhiteSpace(sValue))
                return null;
            Boolean value;
            if (!Boolean.TryParse(sValue, out value))
                return null;
            return value;
        }

        public static IEnumerable<string> GetKeys(String key)
        {
            return ConfigurationManager.AppSettings.AllKeys.Where(p => p.StartsWith(key));
        }

        public static IDictionary<String, String> GetValues(String key)
        {
            var apps = GetKeys(key).ToArray();
            var len = key.Length;
            var aRet = new Dictionary<String, String>(apps.Count());
            foreach (var app in apps)
            {
                aRet.Add(app.Substring(len), GetValue(app));
            }
            return aRet;
        }
    }

}